﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms.DataVisualization.Charting;

namespace Battleship
{
    class StabilityChart
    {
        private ExcelReader reader = new ExcelReader();

        // Dùng cho bảng CROSS
        private double[] LK = new double[Constants.numPhiVol];
        private double[] PhiVol = new double[Constants.numPhiVol];
        private double[] GZ = new double[Constants.numPhiVol];

        // Dùng làm mịn đường cong
        private double[] mPhivol;
        private double[] mLK;
        private double[] mGZ;
        private double step = 0.1;
        private Dictionary<double, double> pairList = new Dictionary<double, double>();

        // Đồ thị diện tích
        private double[] areas;

        // Đồ thị phía bên trái
        private double[] leftPhiVol;
        private double[] leftGZ;

        private double KG;
        private Chart chart;
        private VerticalBalance VB;

        public StabilityChart(double KG, Chart chart, VerticalBalance VB)
        {
            this.VB = VB;
            this.KG = KG;
            this.chart = chart;
            loadData();
            makeSmooth();
            //limitedMomen();
        }

        protected void loadData()
        {
            reader.open(Constants.CROSS_DATA_PATH);

            double waterVol = VB.WaterVol;
            double[] columnVol = new double[Constants.numWaterVol];
            double[] columnLK = new double[Constants.numWaterVol];

            PhiVol[0] = LK[0] = GZ[0] = 0;
            int column = 0;
            //for (int i = 1; i < 10; i++)
            //{
            //    for (int j = 2; j < 24; j++)
            //    {
            //        columnVol[j - 2] = double.Parse(reader.getValue(1, j));
            //        if (columnVol[j - 2] > waterVol)
            //        {
            //            column = j;
            //            break;
            //        }
            //        columnLK[j - 2] = double.Parse(reader.getValue(i + 1, j));
            //    }
            //    myLK[i] = Math.Round(Formulas.Lagrange(waterVol, columnVol, columnLK), 2);
            //}

            for (int j = 2; j < 24; j++)
            {
                columnVol[j - 2] = double.Parse(reader.getValue(1, j));
                if (columnVol[j - 2] > waterVol)
                {
                    column = j;
                    break;
                } 
            }

            for (int i = 1; i < 10; i++)
            {
                PhiVol[i] = double.Parse(reader.getValue(i + 1, 1));
                LK[i] = double.Parse(reader.getValue(i + 1, column));
                GZ[i] = LK[i] - 2.2159 * Math.Sin(PhiVol[i] * Math.PI / 180);
                pairList.Add(PhiVol[i], GZ[i]);
                Console.WriteLine("PhiVol: " + PhiVol[i] + "; LK:" + LK[i] + " => " + "GZ:" + GZ[i]);
            }
            reader.close();
        }

        // Dùng để xuất giá trị trên bảng Static Stability
        public double getGZat30()
        {
            return GZ[3];
        }

        // Tăng số điểm vẽ để làm mịn đường cong
        protected void makeSmooth()
        {
            int numPoint = (int)((PhiVol[9] - PhiVol[0]) / step) + 1;
            mPhivol = new double[numPoint];
            mLK = new double[numPoint];
            mGZ = new double[numPoint];

            mPhivol[0] = PhiVol[0];
            mLK[0] = LK[0];
            mGZ[0] = GZ[0];
            for (int i = 1; i < mPhivol.Length; i++)
            {
                mPhivol[i] = mPhivol[i - 1] + step;
                if (!pairList.Keys.Contains(mPhivol[i]))
                {
                    mLK[i] = Formulas.Lagrange(mPhivol[i], PhiVol, LK);
                    mGZ[i] = mLK[i] - 2.2159 * Math.Sin(mPhivol[i] * Math.PI / 180);
                }
                else
                {
                    mLK[i] = 1;
                    mGZ[i] = pairList[mPhivol[i]];
                }
            }

            // Dùng cho đồ thị thứ 2
            areas = new double[mPhivol.Length];
            areas[0] = 0;
            for (int i = 1; i < mPhivol.Length; i++)
            {
                areas[i] = areas[i - 1] + getPieceArea(i);
            }
        }

        public void draw()
        {
            //for (int j = 0; j < leftPhiVol.Length; j++)
            //{
            //    chart.Series["GZ"].Points.AddXY(leftPhiVol[j], leftGZ[j]);
            //}

            for (int i = 0; i < mPhivol.Length; i++)
            {
                chart.Series["GZ"].Points.AddXY(mPhivol[i], mGZ[i]);
                chart.Series["Ld"].Points.AddXY(mPhivol[i], areas[i]);
            }

            // Draw tangent
            chart.Series["Tangent"].Points.AddXY(0, 0);
            chart.Series["Tangent"].Points.AddXY(57.3, VB.getGM);

            chart.ChartAreas[0].AxisX.Maximum = 100;
            chart.ChartAreas[0].AxisX.Minimum = 0;
            chart.ChartAreas[0].AxisY.Maximum = 3;
            chart.ChartAreas[0].AxisY.Minimum = 0;
            chart.Show();
            chart.SaveImage(Constants.CHART_IMAGE_PATH, ChartImageFormat.Png);
        }

        public double getPieceArea(int n)
        {
            return 0.5 * (mGZ[n] + mGZ[n - 1]) * (Math.PI / 180) * step;
        }

        public void limitedMomen()
        {
            ShakingAmptitude SA = new ShakingAmptitude(VB.WaterVol, VB.getKG);

            double leftXmin = Math.Round(-SA.Biendolac, ((step - (int)step) + "").Length - 2);
            double leftYmin = Formulas.Lagrange(leftXmin, PhiVol, LK)
                                - 2.2159 * Math.Sin(leftXmin * Math.PI / 180);

            int numLeftPoint = (int)(-leftXmin / step);
            leftPhiVol = new double[numLeftPoint + 1];
            leftGZ = new double[numLeftPoint + 1];

            leftPhiVol[0] = leftXmin;
            leftGZ[0] = leftYmin;
            for (int i = 1; i < numLeftPoint; i++)
            {
                leftPhiVol[i] = leftPhiVol[i - 1] + step;
                leftGZ[i] = Formulas.Lagrange(leftPhiVol[i], PhiVol, LK)
                                - 2.2159 * Math.Sin(leftPhiVol[i] * Math.PI / 180);
            }
            leftPhiVol[numLeftPoint] = 0;
            leftGZ[numLeftPoint] = 0;
        }

        public void getRightArea(double Y)
        {
            // TODO
        }

        public void getLeftArea()
        {
            // TODO
        }

        public double getArea30() {
            int index = Int32.Parse((30 / step).ToString());
            return areas[index];
        }

        public double getArea40()
        {
            int index = Int32.Parse((40 / step).ToString());
            return areas[index];
        }

        public double getArea30to40()
        {
            return getArea40() - getArea30();
        }
    }
}
